#!/usr/bin/env python
# -*- coding: utf-8 -*-

from gevent import monkey
monkey.patch_socket()
from gevent import Greenlet
import Singleton
import ThreadSafeSingletion
import ConfigFileData
import SocketTools
import logging
import socket
import time
import ot_pb2
import base_pb2
from pageType import *
import stock_trade_pb2

"""
    1.负责和Robot通信
    2.接收Robot数据，传输到Distribute中。
    3.接收前端指令（提供方法），发送到Robot
"""
@Singleton.singleton
class Connection(Greenlet):
    def __init__(self):
        Greenlet.__init__(self)
        self.queue = ThreadSafeSingletion.SafeQueue()
        self.requesetId = 0
        self.config = ConfigFileData.Data()
        self.packTools = SocketTools.StructProtocol()
        self.request_callback = dict()
        self.RebuildConnection(self.config.get(u'Robot.ip'), int(self.config.get(u'Robot.port')))

    def RebuildConnection(self, ip, port):
        while True:
            try:
                self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.sock.connect((ip, port))
            except:
                logging.warning(u"Robot连接失败, 等待5秒后重新尝试...")
                time.sleep(5)
                continue
            break


    def Recv(self, Packlen):
        ret = str()
        while 1:
            recvBuf = self.sock.recv(Packlen-len(ret))
            if len(recvBuf) == Packlen-len(ret):
                ret += recvBuf
                break
            ret += recvBuf
        return ret

    def RequesetId(self):
        self.requesetId += 1
        return str(self.requesetId)

    def send(self, package_type, message, callBack=None):
        if message:
            message = message.SerializeToString()
        else:
            message = ""
        data = self.packTools.pack([len(message), base_pb2.SYS_MTC, package_type, self.RequesetId()], message)
        ret = self.packTools.get_requestID(self.packTools.GetHeader(data)[3])
        self.sock.sendall(data)
        self.request_callback[ret] = callBack
        return ret

    def _run(self):
        print '[Start]Robot'
        switch = {
            base_pb2.CMD_LOGIN_RESP: self.Handle_Login,
            base_pb2.CMD_SINGLE_ORDER_RESP: self.Handle_SingleOrder,
            base_pb2.CMD_SINGLE_WITHDRAWAL_RESP: self.Handle_SingleOrder,
            base_pb2.CMD_BASKET_ORDER_RESP: self.Handle_BasketOrder,
            base_pb2.CMD_BASKET_WITHDRAWAL_RESP: self.Handle_BasketWithdrawal,
            base_pb2.CMD_BASKET_CUSTOM_RESP: self.Handle_BasketCustom,
            base_pb2.CMD_UNFINISH_BASKET_RESP: self.Handle_BasketUnfinished,   # 自动推回
            base_pb2.CMD_GRADED_FUND_RESP: self.Handle_GradedFund,
            base_pb2.CMD_SUB_ETF_INFO_RESP: self.Handle_SubEtfInfo,
            base_pb2.CMD_SUB_CUSTOM_BASIS_RESP: self.Handle_SubEtfInfo,
            base_pb2.CMD_ETF_ORDER_RESP: self.Handle_SingleOrder,
            base_pb2.CMD_FUND_ORDER_RESP: self.Handle_SingleOrder,

            base_pb2.CMD_HEARTBEAT_REQ: self.Heart,             # 自动推回
            base_pb2.CMD_SUB_ETF_INFO_LIMIT_UP_REQ:     self.Handle_SubEtfInfo_LimitUp,       # 自动推回
            base_pb2.CMD_SUB_ETF_INFO_LIMIT_DOWN_REQ:   self.Handle_SubEtfInfo_LimitDown,     # 自动推回
            base_pb2.CMD_SUB_ETF_INFO_STOP_REQ:         self.Handle_SubEtfInfo_Stop,           # 自动推回
            base_pb2.CMD_SUB_ETF_INFO_MAXPRICE_REQ:     self.Handle_SubEtfInfo_MaxPrice,       # 自动推回
            base_pb2.CMD_SUB_ETF_INFO_MINPRICE_REQ:     self.Handle_SubEtfInfo_MinPrice,       # 自动推回
            base_pb2.CMD_SUB_ETF_INFO_DIOPV_B1_REQ:     self.Handle_SubEtfInfo_DIOPVB1,       # 自动推回
            base_pb2.CMD_SUB_ETF_INFO_DIOPV_S1_REQ:     self.Handle_SubEtfInfo_DIOPVS1,       # 自动推回

            base_pb2.CMD_SUB_ETF_INFO_BASIS_B1_REQ:     self.Handle_SubEtfInfo_Basis_B1,       # 自动推回
            base_pb2.CMD_SUB_ETF_INFO_BASIS_S1_REQ:     self.Handle_SubEtfInfo_Basis_S1,       # 自动推回
            base_pb2.CMD_SUB_ETF_INFO_BASIS_OPEN_REQ:   self.Handle_SubEtfInfo_Basis_Open,     # 自动推回
            base_pb2.CMD_SUB_ETF_INFO_BASIS_CLOSE_REQ:  self.Handle_SubEtfInfo_Basis_Close     # 自动推回
        }
        while True:
            try:
                header = self.Recv(self.packTools.getHeaderLen())
                body = self.Recv(self.packTools.GetBodyLen(header))
                self.packTools.putData(header+body)
            except socket.error, e:
                logging.warning(u"Robot.recv 发生错误:{0}, 重新建立连接...".format(e))
                self.RebuildConnection(self.config.get(u'Robot.ip'), int(self.config.get(u'Robot.port')))
                continue
            except:
                logging.warning(u"Robot:_run:发生未知错误。")
                exit(-1)

            while 1:
                data = self.packTools.getOnce()
                if data:
                    pType = data['head'][2]
                    try:
                        switch[int(pType)](message=data)
                    except:
                        logging.warning(u"Robot处理行情包子类型：{0} 发生错误。".format(pType))
                else:
                    break

    def Handle_SubEtfInfo_LimitUp(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.EtfInfoUpdateReq()
        rep.ParseFromString(message)
        self.queue.put([u'SubEtfInfo_LimitUp', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_SubEtfInfo_LimitDown(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.EtfInfoUpdateReq()
        rep.ParseFromString(message)
        self.queue.put([u'SubEtfInfo_LimitDown', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_SubEtfInfo_Stop(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.EtfInfoUpdateReq()
        rep.ParseFromString(message)
        self.queue.put([u'SubEtfInfo_Stop', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_SubEtfInfo_MaxPrice(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.EtfInfoUpdateReq()
        rep.ParseFromString(message)
        self.queue.put([u'SubEtfInfo_MaxPrice', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_SubEtfInfo_MinPrice(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.EtfInfoUpdateReq()
        rep.ParseFromString(message)
        self.queue.put([u'SubEtfInfo_MinPrice', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_SubEtfInfo_DIOPVB1(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.EtfInfoUpdateReq()
        rep.ParseFromString(message)
        self.queue.put([u'SubEtfInfo_DIOPVB1', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_SubEtfInfo_DIOPVS1(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.EtfInfoUpdateReq()
        rep.ParseFromString(message)
        self.queue.put([u'SubEtfInfo_DIOPVS1', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_SubEtfInfo_Basis_B1(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.EtfInfoUpdateReq()
        rep.ParseFromString(message)
        self.queue.put([u'SubEtfInfo_Basis_B1', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_SubEtfInfo_Basis_S1(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.EtfInfoUpdateReq()
        rep.ParseFromString(message)
        self.queue.put([u'SubEtfInfo_Basis_S1', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_SubEtfInfo_Basis_Open(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.EtfInfoUpdateReq()
        rep.ParseFromString(message)
        self.queue.put([u'SubEtfInfo_Basis_Open', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_SubEtfInfo_Basis_Close(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.EtfInfoUpdateReq()
        rep.ParseFromString(message)
        self.queue.put([u'SubEtfInfo_Basis_Close', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Heart(self, **kwargs):
        data = self.packTools.pack([0, base_pb2.SYS_MTC, base_pb2.CMD_HEARTBEAT_RESP, self.RequesetId()], '')
        self.sock.sendall(data)

    def ExecuteCallBack(self, msg):
        reqID = self.packTools.get_requestID(msg[2])
        if self.request_callback.get(reqID, None):
            self.request_callback[reqID](requestID=reqID, message=msg[1], type=msg[0])

    def Handle_Login(self, **kwargs):
        message = kwargs['message']['body']
        rep = base_pb2.LoginResp()
        rep.ParseFromString(message)
        self.queue.put([u'Login', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_SingleOrder(self, **kwargs):
        message = kwargs['message']['body']
        rep = stock_trade_pb2.SingleOrderResp()
        rep.ParseFromString(message)
        self.queue.put([u'SingleOrder', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_BasketUnfinished(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.BasketUnfinishedResp()
        rep.ParseFromString(message)
        self.queue.put([u'BasketUnfinished', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_BasketOrder(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.BasketPolicyResp()
        rep.ParseFromString(message)
        self.queue.put([u'BasketOrder', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_BasketWithdrawal(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.BasketWithdrawalResp()
        rep.ParseFromString(message)
        self.queue.put([u'BasketWithdrawalResp', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_BasketCustom(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.BasketPolicyResp()
        rep.ParseFromString(message)
        self.queue.put([u'BasketOrder', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_GradedFund(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.PolicyResp()
        rep.ParseFromString(message)
        self.queue.put([u'GradedFund', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])

    def Handle_SubEtfInfo(self, **kwargs):
        message = kwargs['message']['body']
        rep = ot_pb2.EtfInfoSubResp()
        rep.ParseFromString(message)
        self.queue.put([u'SubEtfInfo', rep, self.packTools.get_requestID(kwargs['message']['head'][3])])
